home *** CD-ROM | disk | FTP | other *** search
- /* WIDE AREA INFORMATION SERVER SOFTWARE:
- No guarantees or restrictions. See the readme file for the full standard
- disclaimer.
-
- Brewster@think.com
- */
-
-
- /* This is a simple wais interface for lisp clients.
- * It takes in lisp-y looking requests and sends out Z39.50 packets.
- *
- * -brewster 7/90
- *
- * Important functions:
- * display_search_response
- * main
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include "../ir/ui.h"
-
- #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
- #define MAX_MESSAGE_LEN BUFSZ
- #define VERBOSE false /* true */
-
- /****************************************************************
- *
- * Function Name: display_search_response
- *
- *
- * Purpose: displays the formatted list of documents in the form
- * that the super-text-server would like to see.
- *
- * Returns: nothing.
- *
- * Algorithm: . ...
- *
- */
-
-
- /* modified from tracy shen's version in wutil.c
- * displays a set of headlines.
- */
- void
- display_search_response(response,database,server_name,service_name)
- SearchResponseAPDU *response;
- char *database;
- char *server_name;
- char *service_name;
- {
- WAISSearchResponse *info;
- long k;
- printf("(:query (");
-
- if ( response->DatabaseDiagnosticRecords != 0 ) {
- info = response->DatabaseDiagnosticRecords;
- if(info->DocHeaders != 0){
- k =0;
- while(info->DocHeaders[k] != 0 ){
- char doc_id[1000];
- strncpy(doc_id, info->DocHeaders[k]->DocumentID->bytes,
- MIN(info->DocHeaders[k]->DocumentID->size, 1000));
- doc_id[MIN(info->DocHeaders[k]->DocumentID->size, 1000 - 1)]
- = '\0';
- printf("(:doc-id \"%s\" :document-length %ld :types (\"%s\") :database-name \"%s\" :server-name \"%s\" :score %ld :service \"%s\" :header \"",
- doc_id,
- info->DocHeaders[k]->DocumentLength,
- (info->DocHeaders[k]->Types == NULL)?"TEXT":info->DocHeaders[k]->Types[0],
- database,
- server_name,
- info->DocHeaders[k]->Score,
- service_name
- );
- { char *header = trim_junk(info->DocHeaders[k]->Headline);
- long i;
- for(i=0; i < strlen(header); i++){
- char ch = header[i];
- if(ch == '"')
- putc('\\', stdout);
- putc(ch, stdout);
- }
- }
- printf("\")");
- k++;
- }
- }
- }
- printf(")\n:end t)\n"); /* finish it */
- fflush(stdout);
- }
-
-
- /*******************
- * Parsing *
- *******************/
-
- /* In a alist of keys and values,
- * this finds the string value associated with a key.
- * The way this is implemented is a kludge since it searches for
- * the key with string search rather than making a list and
- * searching down it. This can error if a value contains a string version
- * of the key.
- * What we really need is list facilities.
- *
- * Side effects value.
- * Returns 0 if it wins, 1 if there is no such slot, -1 if error.
- */
-
- /* these are states of the parser */
- #define BEFORE 1
- #define DURING 2
- #define QUOTE 5
-
- long find_string_slot(source,key,value,value_size,delete_internal_quotes)
- char *source;
- char *key;
- char *value;
- long value_size;
- boolean delete_internal_quotes;
- {
- char ch;
- short state = BEFORE;
- long position = 0; /* position in value */
- char *pos =strstr(source, key); /* address into source */
-
- value[0] = '\0'; /* initialize to nothing */
-
- if(NULL == pos)
- return(1);
-
- for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
- ch = *pos;
- if((state == BEFORE) && (ch == '\"'))
- state = DURING;
- else if ((state == DURING) && (ch == '\\')){
- state = QUOTE;
- if(!delete_internal_quotes){
- value[position] = ch;
- position++;
- if(position >= value_size){
- value[value_size - 1] = '\0';
- return(-1);
- }
- }
- }
- else if ((state == DURING) && (ch == '"')){
- value[position] = '\0';
- return(0);
- }
- else if ((state == QUOTE) || (state == DURING)){
- if(state == QUOTE)
- state = DURING;
- value[position] = ch;
- position++;
- if(position >= value_size){
- value[value_size - 1] = '\0';
- return(-1);
- }
- }
- /* otherwise we are still before the start of the value */
- }
- value[position] = '\0';
- return(-1); /* error because we are in the middle of the string */
- }
-
- /* reads a long int a file returns true if successful, false otherwise */
- long find_long_slot(source,key,answer)
- char *source;
- char *key;
- long *answer;
- {
- char ch;
- short state = BEFORE;
- char *pos =strstr(source, key); /* address into source */
- long count = 0;
- boolean isNegative = false;
- *answer = 0;
-
- if(NULL == pos)
- return(1);
-
- for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
- ch = *pos;
- if (isdigit(ch)){
- if(state == BEFORE){
- state = DURING;
- }
- count++;
- if(count == 12){
- /* then we have an error in the file, 32 bit numbers can not be more
- than 10 digits long */
- return(-1);
- }
- *answer = *answer * 10 + (ch - '0');
- }
- else if (ch == '-') {
- if (isNegative)
- /* then we have an error since there should be only one - in a number */
- return(-1);
- if (state == BEFORE) {
- /* we are ok since the - must come before any digits */
- isNegative = true;
- state = DURING;
- }
- else {
- break; /* we are done */
- }
- }
- else if(!isspace(ch)){
- /* then we have an error since it should be a digit or a space */
- return(-1);
- }
- /* we do not have an digit */
- else if(state == DURING){
- break; /* we are done */
- }
- /* otherwise we are still before the start */
- }
- if (isNegative)
- *answer *= -1;
- return(0);
- }
-
-
-
- /************
- * MAIN *
- ************/
-
- #define MAX_QUERY_SIZE 10000
- #define MAX_NAME_SIZE 1000
- void main()
- {
- char query[MAX_QUERY_SIZE + 1];
- char request_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
- char response_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
- long request_buffer_length; /* how of the request is left */
- SearchResponseAPDU *query_response;
- SearchResponseAPDU *retrieval_response;
- char service[MAX_NAME_SIZE + 1];
- char database[MAX_NAME_SIZE + 1];
- char server_name[MAX_NAME_SIZE + 1];
- char type[MAX_NAME_SIZE + 1];
-
- server_name[0] = '\0'; /* null it out */
- database[0] = '\0'; /* null it out */
- service[0] = '\0'; /* null it out */
-
- while(TRUE){
- /* continue to search until the user gets tired */
-
- fgets(query, MAX_QUERY_SIZE, stdin);
- if(NULL != strstr(query, ":fill-in") ||
- NULL != strstr(query, ":query")){
- /* then we have a fill-in or query.
- extract the common fields */
-
- if(0 > find_string_slot(query, ":database", database,
- MAX_NAME_SIZE, false)){
- panic("Could not read the database from query %s", query);
- }
- if(0 > find_string_slot(query, ":server", server_name,
- MAX_NAME_SIZE, false)){
- panic("Could not read the host from query %s", query);
- }
- if(0 > find_string_slot(query, ":service", service,
- MAX_NAME_SIZE, false)){
- panic("Could not read the service from query %s", query);
- }
- }
-
- if(NULL != strstr(query, ":fill-in")){
- /* then we have a fill-in request */
- long count;
- long document_length;
- char doc_id[MAX_NAME_SIZE + 1];
- any doc_id_any;
- if(0 != find_string_slot(query, ":doc-id", doc_id,
- MAX_NAME_SIZE, false)){
- panic("Could not read the doc-id from request %s", query);
- }
- doc_id_any.bytes = doc_id;
- doc_id_any.size = strlen(doc_id);
-
- if(0 != find_long_slot(query, ":document-length", &document_length)){
- panic("Could not read the document length from doc_id %s", query);
- }
- if(0 != find_string_slot(query, ":type", type,
- MAX_NAME_SIZE, false)){
- panic("Could not read the type from request %s", query);
- }
-
- printf("(:fill-in (:text \""); /* start the reply */
- for(count = 0;
- count * CHARS_PER_PAGE < document_length;
- count++){
- request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
- if(NULL ==
- generate_retrieval_apdu(request_message + HEADER_LENGTH,
- &request_buffer_length,
- &doc_id_any,
- CT_byte,
- count * CHARS_PER_PAGE,
- MIN((count + 1) * CHARS_PER_PAGE,
- document_length),
- type,
- database
- ))
- panic("query was too large");
-
- if(0 ==
- interpret_message(request_message,
- MAX_MESSAGE_LEN - request_buffer_length,
- response_message,
- MAX_MESSAGE_LEN,
- server_name,
- service,
- VERBOSE
- ))
- panic("return message too large");
-
- readSearchResponseAPDU(&retrieval_response,
- response_message + HEADER_LENGTH);
- if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text)
- panic("No text was returned");
-
- display_text_record_completely
- (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], true);
- }
- printf("\")\n:end t)\n"); /* finish the text */
- fflush(stdout);
- }
- else if(NULL != strstr(query, ":query")){
- /* then we have a query */
- char seed_words[MAX_QUERY_SIZE + 1];
- if(0 != find_string_slot(query, ":seed-words", seed_words,
- MAX_QUERY_SIZE, false)){
- panic("Could not read the seed words from query %s", query);
- }
- request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
- if(NULL ==
- generate_search_apdu(request_message + HEADER_LENGTH,
- &request_buffer_length,
- seed_words, database, NULL))
- panic("Query was too large");
-
- if(0 ==
- interpret_message(request_message,
- MAX_MESSAGE_LEN - request_buffer_length,
- response_message,
- MAX_MESSAGE_LEN,
- server_name,
- service,
- VERBOSE
- ))
- panic("return message too large");
-
- readSearchResponseAPDU(&query_response,
- response_message + HEADER_LENGTH);
- display_search_response(query_response, database, server_name,
- service);
- }
- else
- panic("Dont know how to handle query %s\n", query);
- }
- }
-
-
- /* sample
- (:query :seed-words ("food") :database "/u/kahle/wais-index-irn8/foo" :server "gandalf" :service "8000")
- */
-